//
// Created by HP on 2025/11/14.
//
////
//// Created by HP on 2025/11/10.
////
//
#include "../include/database.h"
#include <iostream>
#include <utility>

DBConnector* DBConnector::instance_ = nullptr;

DBConnector::DBConnector(std::string  host, std::string  user,
                         std::string  passwd, std::string  dbname,
                         unsigned int port)
        : db(QSqlDatabase()), host_(std::move(host)), user_(std::move(user)), passwd_(std::move(passwd)), dbname_(std::move(dbname)), port_(port) {

}

DBConnector::~DBConnector() {
    if (db.isValid() && db.isOpen()) {
        db.close();
    }
}

bool DBConnector::connect() {
    if (instance_ != nullptr) {
        std::cerr<<"Only one instance of DBConnector is allowed."<<std::endl;
        return false;
    }
    // 使用 ODBC 驱动
    // 需要系统已安装 MySQL ODBC 8.x Driver，并且 Qt 的 qsqlodbc 插件可用
    if (!db.isValid()) {
        db = QSqlDatabase::addDatabase("QODBC");
    }
    // 优先使用无 DSN 连接串，避免系统未配置 DSN 导致失败
    const QString host = QString::fromStdString(host_);
    const QString dbname = QString::fromStdString(dbname_);
    const QString user = QString::fromStdString(user_);
    const QString pass = QString::fromStdString(passwd_);
    const QString port = QString::number(static_cast<int>(port_));

    // 使用 compose.yml 中传入的参数直连（无 DSN），驱动名以 ODBC 管理器所示为准
    QString connStr = QStringLiteral("Driver={MySQL ODBC 9.5 ANSI Driver};Server=%1;Database=%2;User=%3;Password=%4;Port=%5;")
            .arg(host, dbname, user, pass, port);
    db.setDatabaseName(connStr);
    if (!db.open()) {
        // 回退尝试 Unicode 变体（不同机器可能只安装了 Unicode 版）
        db.close();
        connStr = QStringLiteral("Driver={MySQL ODBC 9.5 Unicode Driver};Server=%1;Database=%2;User=%3;Password=%4;Port=%5;")
                .arg(host, dbname, user, pass, port);
        db.setDatabaseName(connStr);
        if (!db.open()) return false;
    }
    if (instance_ == nullptr){
        instance_ = this;
    }
    return true;
}

/**
 * 执行SQL查询并返回结果集
 * @param sql 要执行的SQL语句
 * @return 包含查询结果的二维map结构，外层vector代表行，内层map代表字段名和值的对应关系
 */
std::vector<std::map<std::string, std::string>> DBConnector::query(const std::string& sql) {
    // 创建结果容器
    std::vector<std::map<std::string, std::string>> result;
    // 检查数据库连接是否有效且已打开
    if (!db.isValid() || !db.isOpen()) {
        return result;
    }

    // 创建SQL查询对象
    QSqlQuery q(db);
    // 执行SQL查询，如果执行失败则返回空结果
    if (!q.exec(QString::fromStdString(sql))) {
        return result;
    }

    // 获取记录信息
    QSqlRecord rec = q.record();
    // 获取字段数量
    int fieldCount = rec.count();
    // 遍历查询结果的每一行
    while (q.next()) {
        // 创建行数据map
        std::map<std::string, std::string> rowData;
        // 遍历每个字段
        for (int i = 0; i < fieldCount; ++i) {
            // 获取字段名
            QString fieldName = rec.fieldName(i);
            // 获取字段值
            QString value = q.value(i).toString();
            // 将字段名和值存入map
            rowData[fieldName.toStdString()] = value.toStdString();
        }
        // 将行数据添加到结果集中
        result.push_back(std::move(rowData));
    }
    return result;
}

/**
 * 执行SQL语句并返回受影响的行数
 * @param sql 要执行的SQL语句字符串
 * @return 成功执行返回受影响的行数，失败返回-1
 */
int DBConnector::execute(const std::string& sql) {
    // 检查数据库连接是否有效且已打开
    if (!db.isValid() || !db.isOpen()) {
        return -1;
    }
    // 创建 QSqlQuery 对象并关联到数据库连接
    QSqlQuery q(db);
    // 执行SQL语句，如果执行失败则返回-1
    if (!q.exec(QString::fromStdString(sql))) {
        return -1;
    }
    // 对于非查询语句，Qt 无法总是直接得出受影响行数，这里尝试用 numRowsAffected
    return q.numRowsAffected();
}

std::string DBConnector::getError() {
    if (db.isValid()) {
        return db.lastError().text().toStdString();
    }
    return "未初始化连接";
}

DBConnector *DBConnector::getInstance() {
    return instance_;
}
